#include "board.h"
#include "gd32_rcu.h"
#include "gd32f3x0_rcu.h"
#include "system_gd32f3x0.h"

//PLL = 120M
//AHB = 120M
//APB1 = 60M
//APB2 = 60M
int BOARD_Clock_Init() {
    uint32_t timeout = 0U;

    // select IRC8M as SYSCLK
    if (R_RCU_CFG0->SCSS != 0b00) {
        R_RCU_CTL0->IRC8MEN = 1;
        /* wait until IRC8MEN is stable */
        while (!R_RCU_CTL0->IRC8MSTB) {}
        R_RCU_CFG0->SCS = 0b00;
        while (R_RCU_CFG0->SCSS != 0b00) {}
    }

    /* enable HXTAL */
    R_RCU_CTL0->HXTALEN = 1;
    /* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
    while (TRUE) {
        timeout++;
        if (R_RCU_CTL0->HXTALSTB) { break; }
        if (timeout > HXTAL_STARTUP_TIMEOUT) { return -1; }
    }
    /* HXTAL is stable */

    /* AHB = SYSCLK and APBx=...*/
    R_RCU_CFG0->AHBPSC = AHB_Prescaler_1;
    R_RCU_CFG0->APB1PSC = APBx_Prescaler_2;
    R_RCU_CFG0->APB2PSC = APBx_Prescaler_2;


    /* PLL = HXTAL /2 * 30 = 120 MHz */
    R_RCU_CTL0->PLLEN = 0;
    R_RCU_CFG1->PLLPRESEL = 0;// 0:HXTAL 1:IRC48M
    R_RCU_CFG1->PREDV = 1;// /2
    R_RCU_CFG0->PLLSEL = 1; //0IRC8M/2 1HXTAL
    R_RCU_CFG0->PLLMF = 28u & 0b1111; // x30
    R_RCU_CFG0->PLLMF_4 = 28u >> 4; // x30
    R_RCU_CFG1->PLLMF_5 = 28u >> 5; // x30
    R_RCU_CTL0->PLLEN = 1;

    /* enable PLL */
    R_RCU_CTL0->PLLEN = 1;
    /* wait until PLL is stable */
    while (!R_RCU_CTL0->PLLSTB) {}

    /* select PLL as system clock */
    R_RCU_CFG0->SCS = 0b10;
    /* wait until PLL is selected as system clock */
    while (R_RCU_CFG0->SCSS != 0b10) {}

    //disable IRC8M
    R_RCU_CTL0->IRC8MEN = 0;

    // set clock for the other peripherals

    //usb ck = 120M/2.5 = 48M
    R_RCU_CFG0->USBFSPSC = USBFS_Prescaler_2dot5;
    R_RCU_CFG2->USBFSPSC_2 = USBFS_Prescaler_2dot5 >> 2;
    R_RCU_ADDCTL->CK48MSEL = 0;
//    SystemCoreClockUpdate();
    SystemCoreClock = 120000000;
    return 0;
}

//PLL = 168M
//AHB = 168M
//APB1 = 84M
//APB2 = 84M
int BOARD_Clock_FullSpeed_Init() {
    uint32_t timeout = 0U;

    // select IRC8M as SYSCLK
    if (R_RCU_CFG0->SCSS != 0b00) {
        R_RCU_CTL0->IRC8MEN = 1;
        /* wait until IRC8MEN is stable */
        while (!R_RCU_CTL0->IRC8MSTB) {}
        R_RCU_CFG0->SCS = 0b00;
        while (R_RCU_CFG0->SCSS != 0b00) {}
    }

    /* enable HXTAL */
    R_RCU_CTL0->HXTALEN = 1;
    /* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
    while (TRUE) {
        timeout++;
        if (R_RCU_CTL0->HXTALSTB) { break; }
        if (timeout > HXTAL_STARTUP_TIMEOUT) { return -1; }
    }
    /* HXTAL is stable */

    /* AHB = SYSCLK and APBx=...*/
    R_RCU_CFG0->AHBPSC = AHB_Prescaler_1;
    R_RCU_CFG0->APB1PSC = APBx_Prescaler_2;
    R_RCU_CFG0->APB2PSC = APBx_Prescaler_2;


    /* PLL = HXTAL /2 * 42 = 168 MHz */
    R_RCU_CTL0->PLLEN = 0;
    R_RCU_CFG1->PLLPRESEL = 0;// 0:HXTAL 1:IRC48M
    R_RCU_CFG1->PREDV = 1;// /2
    R_RCU_CFG0->PLLSEL = 1; //0IRC8M/2 1HXTAL
    R_RCU_CFG0->PLLMF = 40u & 0b1111; // x42
    R_RCU_CFG0->PLLMF_4 = 0b1 & (40u >> 4); // x42
    R_RCU_CFG1->PLLMF_5 = 40u >> 5; // x42
    R_RCU_CTL0->PLLEN = 1;

    /* enable PLL */
    R_RCU_CTL0->PLLEN = 1;
    /* wait until PLL is stable */
    while (!R_RCU_CTL0->PLLSTB) {}

    /* select PLL as system clock */
    R_RCU_CFG0->SCS = 0b10;
    /* wait until PLL is selected as system clock */
    while (R_RCU_CFG0->SCSS != 0b10) {}

    //disable IRC8M
    R_RCU_CTL0->IRC8MEN = 0;

    // set clock for the other peripherals

    // usb ck = 168M/3.5 = 48M
    R_RCU_CFG0->USBFSPSC = 0b11 & USBFS_Prescaler_3dot5;
    R_RCU_CFG2->USBFSPSC_2 = USBFS_Prescaler_3dot5 >> 2;
    R_RCU_ADDCTL->CK48MSEL = 0;
    SystemCoreClock = 168000000;
    return 0;
}

void BOARD_clock_108m_irc8m(void)
{
    /* AHB = SYSCLK */
    RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
    /* APB2 = AHB/2 */
    RCU_CFG0 |= RCU_APB2_CKAHB_DIV2;
    /* APB1 = AHB/2 */
    RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
    /* PLL = (IRC8M/2) * 27 = 108 MHz */
    RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PLLMF | RCU_CFG0_PLLMF4 | RCU_CFG0_PLLPREDV);
    RCU_CFG1 &= ~(RCU_CFG1_PLLPRESEL | RCU_CFG1_PLLMF5 | RCU_CFG1_PREDV);
    RCU_CFG0 |= (RCU_PLLSRC_IRC8M_DIV2 | (RCU_PLL_MUL27 & (~RCU_CFG1_PLLMF5)));
    RCU_CFG1 |= (RCU_PLL_MUL27 & RCU_CFG1_PLLMF5);

    /* enable PLL */
    RCU_CTL0 |= RCU_CTL0_PLLEN;

    /* wait until PLL is stable */
    while (0U == (RCU_CTL0 & RCU_CTL0_PLLSTB)) {
    }

    /* select PLL as system clock */
    RCU_CFG0 &= ~RCU_CFG0_SCS;
    RCU_CFG0 |= RCU_CKSYSSRC_PLL;

    /* wait until PLL is selected as system clock */
    while (0U == (RCU_CFG0 & RCU_SCSS_PLL)) {
    }
}

int BOARD_GPIO_Init()
{
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_GPIOB);

    //    gpio_mode_set(LED0_GPIO, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED0_PIN);
    //    gpio_output_options_set(LED0_GPIO, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, LED0_PIN);
    //
    //    gpio_mode_set(LED1_GPIO, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED1_PIN);
    //    gpio_output_options_set(LED1_GPIO, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, LED1_PIN);
    //
//    //TIM1
//    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);
//    gpio_af_set(GPIOA, GPIO_AF_2, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);
//    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);


    //adc
//    gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
//    gpio_mode_set(GPIOB, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_0 | GPIO_PIN_1);

    //uart0
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9 | GPIO_PIN_10);
    gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_9 | GPIO_PIN_10);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_9 | GPIO_PIN_10);

    //usb
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_11 | GPIO_PIN_12);
    gpio_af_set(GPIOA, GPIO_AF_5, GPIO_PIN_11 | GPIO_PIN_12);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_11 | GPIO_PIN_12);


//    //i2c0
//    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_6 | GPIO_PIN_7);
//    gpio_af_set(GPIOB, GPIO_AF_1, GPIO_PIN_6 | GPIO_PIN_7);
//    gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_10MHZ, GPIO_PIN_6 | GPIO_PIN_7);

    //TIM15
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_6);
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_6);
    gpio_af_set(GPIOA, GPIO_AF_5, GPIO_PIN_6);
    gpio_af_set(GPIOB, GPIO_AF_2, GPIO_PIN_6);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_6);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_6);
    return 0;
}
#include "gd32f3x0_adc.h"
#include "gd32f3x0_timer.h"
#include "gd32f3x0_usart.h"
#include "gd32f3x0_i2c.h"

int BOARD_Peripherals_Init() {

    //TIM1 120M时钟
    timer_oc_parameter_struct timer_ocintpara;
    timer_parameter_struct timer_initpara;
    timer_break_parameter_struct timer_breakpara;

    rcu_periph_clock_enable(RCU_TIMER15);

    timer_deinit(TIMER15);
    timer_initpara.prescaler = 19;//10m
    timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection = TIMER_COUNTER_UP;
    timer_initpara.period = 10000 - 1;//1k
    timer_initpara.clockdivision = TIMER_CKDIV_DIV4;
    timer_initpara.repetitioncounter = 0;
    timer_init(TIMER15, &timer_initpara);

    /* CH0/CH0N configuration in PWM mode0 */
    timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
    timer_ocintpara.outputnstate = TIMER_CCXN_ENABLE;
    timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_LOW;
    timer_ocintpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
    timer_ocintpara.ocidlestate = TIMER_OC_IDLE_STATE_HIGH;
    timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;

    timer_channel_output_config(TIMER15, TIMER_CH_0, &timer_ocintpara);

    timer_channel_output_pulse_value_config(TIMER15, TIMER_CH_0, 399);
    timer_channel_output_mode_config(TIMER15, TIMER_CH_0, TIMER_OC_MODE_PWM0);
    timer_channel_output_shadow_config(TIMER15, TIMER_CH_0, TIMER_OC_SHADOW_DISABLE);

    /* automatic output enable, break, dead time and lock configuration*/
    timer_breakpara.runoffstate = TIMER_ROS_STATE_DISABLE;
    timer_breakpara.ideloffstate = TIMER_IOS_STATE_DISABLE;
    timer_breakpara.deadtime = 255; // TODO 修改死区时间
    timer_breakpara.breakpolarity = TIMER_BREAK_POLARITY_LOW;
    timer_breakpara.outputautostate = TIMER_OUTAUTO_ENABLE;
    timer_breakpara.protectmode = TIMER_CCHP_PROT_0;
    timer_breakpara.breakstate = TIMER_BREAK_ENABLE;
    timer_break_config(TIMER15, &timer_breakpara);

    /* TIMER0 primary output function enable */
    timer_primary_output_config(TIMER15, ENABLE);

    /* auto-reload preload enable */
    timer_auto_reload_shadow_enable(TIMER15);

    /* TIMER0 counter enable */
    timer_enable(TIMER15);

    //adc

    //uart0
    /* enable USART clock */
    rcu_periph_clock_enable(RCU_USART0);

    /* USART configure */
    usart_deinit(USART0);
    usart_word_length_set(USART0, USART_WL_8BIT);
    usart_stop_bit_set(USART0, USART_STB_1BIT);
    usart_parity_config(USART0, USART_PM_NONE);
    usart_baudrate_set(USART0, 1152000U);
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);

    usart_enable(USART0);
    //usb

    //i2c0

    return 0;
}
void UART_Send(uint32_t reg, const char *d, uint32_t len) {
    for (int i = 0; i < len; ++i) {
        USART_TDATA(reg) = (USART_TDATA_TDATA & d[i]);
        while (RESET == usart_flag_get(reg, USART_FLAG_TBE));
    }
}
